#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

static __data char radix ;
static __bit  long_flag = 0;
static __bit  string_flag = 0;
static __bit  char_flag = 0;
static char * __data str ;
static __data long val;

#if NICE_LIFO_IMPLEMENTATION_BUT_NOT_PORTABLE
/* just for the SP */
#include <8051.h>

static __data volatile char ch;
static __bit sign;

static void pval( void ) {
  volatile char sp;
  unsigned long lval;
  sp = SP;
  if( val < 0 && radix != 16 ) {
    lval = -val;
    sign = 1;
  } else {
    sign = 0;
    lval = val;
  }
  if( !long_flag ) {
    lval &= 0x0000ffff;
  }
  if( char_flag ) {
    lval &= 0x000000ff;
  }
  do {
    #  if 1
    if( radix != 16 )  {
      ch = ( lval % radix ) + '0';
    } else {
      ch = "0123456789ABCDEF"[( unsigned char )lval & 0x0f];
    }
    __asm push _ch __endasm;
    lval /= radix;
    #  else
    // This only looks more efficient, but isn't. see the .map
    ch = ( lval % radix ) + '0';
    if( ch > '9' ) {
      ch += 7;
    }
    __asm push _ch __endasm;
    lval /= radix;
    #  endif
  } while( lval );
  if( sign ) {
    ch = '-';
    __asm push _ch __endasm;
  }
  while( sp != SP ) {
    __asm pop _ch __endasm;
    putchar( ch );
  }
}
#endif

void printf_small( char * fmt, ... ) __reentrant {
  va_list ap ;

  va_start( ap, fmt );

  for( ; *fmt ; fmt++ ) {
    if( *fmt == '%' ) {
      long_flag = string_flag = char_flag = 0;
      fmt++ ;
      switch( *fmt ) {
        case 'l':
          long_flag = 1;
          fmt++;
          break;
        case 'h':
          char_flag = 1;
          fmt++;
      }
      switch( *fmt ) {
        case 's':
          string_flag = 1;
          break;
        case 'd':
          radix = 10;
          break;
        case 'x':
          radix = 16;
          break;
        case 'c':
          radix = 0;
          break;
        case 'o':
          radix = 8;
          break;
      }
      if( string_flag ) {
        str = va_arg( ap, char * );
        while( *str ) {
          putchar( *str++ );
        }
        continue ;
      }
      if( long_flag )
      { val = va_arg( ap, long ); }
      else if( char_flag )
      { val = va_arg( ap, char ); }
      else
      { val = va_arg( ap, int ); }
      #if NICE_LIFO_IMPLEMENTATION_BUT_NOT_PORTABLE
      if( radix ) {
        pval();
      }
      #else
      if( radix ) {
        static char __idata buffer[12]; /* 37777777777(oct) */
        char __idata * stri;
        _ltoa( val, buffer, radix );
        stri = buffer;
        while( *stri ) {
          putchar( *stri );
          stri++;
        }
      }
      #endif
      else
      { putchar( ( char )val ); }
    } else
    { putchar( *fmt ); }
  }
}
